package Master;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.swing.JOptionPane;

import Master.interfaces.*;
import Module.*;
import Module.StatusService.*;

/**
 * Created by IntelliJ IDEA.
 * User: lihengfeng
 * Date: 11-5-19
 * Time: 
 * To change this template use File | Settings | File Templates.
 */
public class WorkerMonitor implements Runnable{

	private Hashtable<Integer, JobStatus> jobsStatus;
	private Hashtable<Integer, WorkerStatus> workerStatus;
	private ArrayList<Resource> resources;
	private StatusService statusService;
	/*private boolean isRunning;*/
	private int timeLength = 500;
	private TaskPlan taskPlan=null;
	private int numOfJobs;
	private  InputScreen inputscreen_gui;
	private MonitorScreen monitor_gui;
	
	public WorkerMonitor(TaskPlan taskPlan, InputScreen inputscreen_gui){
		this.taskPlan=taskPlan;
		this.resources = taskPlan.getResources();
		/*this.isRunning = true;*/
		this.numOfJobs = taskPlan.getTasks().size();
		this.inputscreen_gui=inputscreen_gui;
		this.workerStatus=new Hashtable<Integer, WorkerStatus>();
	}
	
	public void run() {
		// TODO Auto-generated method stub
		Enumeration<Integer>  jobIDs;
		int jobID;
		JobStatus jobStatus;
		int finishedJobs, currentJobID;
		boolean[] currentJobsDone;
		monitor_gui=new MonitorScreen();
		this.monitor_gui.setInputScreen(inputscreen_gui);
		this.monitor_gui.initWorkerStatus();
		this.monitor_gui.initJobStatus(taskPlan);
		this.monitor_gui.setStartInfo(taskPlan);
		this.monitor_gui.startup();
		
		/*while(isRunning){*/
		while(true){
			//System.out.println("he");
			finishedJobs = 0;
			for(Resource resource : resources){
				//resource.clearFinshedJobs();
				System.out.println("resource ID = " + resource.getID());
				System.out.println("resource Available = " + resource.isAvailable());
                if(resource.isAvailable()){
                    statusService = resource.getStatusService();
                    try {
                        jobsStatus = statusService.getJobsStatus(resource.getAuthCode());
                        this.workerStatus.put(resource.getID(), 
                        		statusService.getWorkerStatus(resource.getAuthCode()));
                    } catch (RemoteException e) {
                        // TODO Auto-generated catch block
                    	System.out.println("ERRRRRRRRRRRRRRRRRRRRRRO");
                        e.printStackTrace();
                    	//this.workerStatus.put(resource.getID(), StatusService.WorkerStatus.dead);
                    	continue;
                    }
                    //System.out.println(this.getClass() + "######" + jobsStatus.size());
                    jobIDs = jobsStatus.keys();
                    currentJobsDone = new boolean[jobsStatus.size()];
                    for(int i = 0; i < currentJobsDone.length; i++){
                        currentJobsDone[i] = false;
                    }
                    currentJobID = 0;
                    while(jobIDs.hasMoreElements()){
                        jobID = jobIDs.nextElement();
                        jobStatus = jobsStatus.get(jobID);
                        System.out.printf("Resource: %d, Job: %d, Status: %s\n",
                                resource.getID(), jobID, jobStatus);
                        this.monitor_gui.updateJobStatus(resource.getID(), jobID, jobStatus);

                        if(currentJobsDone[currentJobID] == false &&
                                (jobStatus == JobStatus.done ||
                                        jobStatus == JobStatus.cancel )){
                            currentJobsDone[currentJobID] = true;
                            //System.out.println("finshed jobs num = " + resource.getFinishedJobs());
                            //resource.incFinishedJobs();
                            finishedJobs++;
                        }
                        currentJobID++;
                    }
                }
                else {
                	System.out.println("Resource is dead " + resource.getID());
                	finishedJobs += resource.getFinishedJobs();
                    if(resource.isReschedule() == false){
                        //reallocate jobs
                        ArrayList<Task> unfinishedTasks = resource.getUnfinishedTasks();
                        

                        System.out.println("$$$$$$$$$$$ Unfinished task size" + 
                        		unfinishedTasks.size());
                        
                        /*ArrayList<Resource> availableRes = new ArrayList<Resource>();
                        for(Resource r : resources){
                        	if(r.isAvailable()){
                        		availableRes.add(r);
                        	}
                        }*/
                        
                        boolean[] resAvailable = new boolean[resources.size()];
                        for(int j = 0; j < resAvailable.length; j++)
                        	resAvailable[j] = true;
                        int resCounter = 0;
                        int taskCounter = 0;
                        Resource res;
                        while(true){
                        	res = resources.get(resCounter);
                        	if(res.isAvailable()){
                        		// if resource is available, then assign the task to this resource
                        		res.addTask(unfinishedTasks.get(taskCounter));
                        		// the counter of assigned tasks increased 
                        		taskCounter++;
                        		if(taskCounter == unfinishedTasks.size()){
                        			// if the unfinished tasks are all assigned then break
                        			break;
                        		}
                        	}
                        	else{
                        		resAvailable[resCounter] = false;
                        	}
                        	resCounter++;
                        	if(resCounter == resources.size()){
                        		resCounter = 0;
                        	}
                        	
                        	int j;
                        	for(j = 0; j < resAvailable.length; j++){
                        		if(resAvailable[j]){
                        			break;
                        		}
                        	}
                        	if(j == resAvailable.length) break;
                        }
                        
                        /*
                        for(Task task : unfinishedTasks) {
                            System.out.println("Unfinished jobs :" + task.getTaskID());
                            for(Resource res : resources){
                                if(res.isAvailable()){
                                	System.out.println("New job assigned to " + res.getID());
                                    res.addTask(task);
                                    break;
                                }
                            }
                        }*/

                        resource.setReschedule(true);
                    }
                    
                    this.workerStatus.put(resource.getID(), StatusService.WorkerStatus.dead);
                    System.out.println("Worker " + resource.getID() + " is dead");
                }
			}
			this.monitor_gui.updateWorkerStatus(workerStatus);

            this.monitor_gui.updateProgressBar((finishedJobs * 100) / this.numOfJobs);

            try {
				Thread.sleep(timeLength);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("finishedJobs = " + finishedJobs);
			if(finishedJobs == this.numOfJobs){
				float maxTime = 0.0f, totalCost = 0.0f, totalTime = 0.0f;
				for(Resource resource : resources){
					/**
					 * Calculate time and cost
					 */
					totalTime = 0.0f;
					ArrayList<Task> tasks =  resource.getTasks();
					for(Task task : tasks){
						totalCost += task.getTotalCost();
						totalTime += task.getElapsedTime();
					}
					if(totalTime > maxTime) maxTime = totalTime;
					this.monitor_gui.setFinishedInfo(maxTime, totalCost);
					if(totalCost > taskPlan.getBudget()){
						JOptionPane.showMessageDialog(null,"The actual cost exceeds the " +
								"given budget. Penalty imposed!",
								"Info",JOptionPane.INFORMATION_MESSAGE);
					}
					/**
					 * Clear resource status
					 */
                    if(resource.isAvailable()){
                        try {
                            resource.getStatusService().clearStatus(resource.getAuthCode());
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }
				break;
			}	
		}
		PriorityQueue priorityQueue = this.inputscreen_gui.getPriorityQueue();
		if(priorityQueue.getTaskPlans().size() != 1){
			this.inputscreen_gui.execution_procedure();
		}
		else{
			this.inputscreen_gui.getExecute_btn().setEnabled(true);
		}
		//System.out.println("here 3");
		
	}
	
	
}
